package com.googlecode.hibernate.memcached;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.UUID;
import java.util.regex.Pattern;

/**
 * Cleans a concatenated string to be used as the cache key.
 * By default this class uses the
 * {@link com.googlecode.hibernate.memcached.AbstractKeyStrategy#convertKeyToString(String, long, Object)}
 * method to get a String for use as the key and then removes all white space.
 * <p/>
 * Memcached keys are limited to 250 characters in length.
 * If the key generated by this strategy exceeds that length, it is automatically truncated via encoding.
 * The default encoding is done by using the {@link UUID#nameUUIDFromBytes(byte[])} functionality introduced in Java 5.
 * Essentially the long key name is hashed using MD5 and divided into segments to comply with UUID standards.
 * <p/>
 * Subclasses can override the {@link #truncateKey(String)} method to provide custom behavior.
 *
 * @author Ray Krueger
 */
public class DefaultKeyStrategy extends AbstractKeyStrategy {

    public static final int DEFAULT_MAX_KEY_LENGTH = 250;

    private static final Log log = LogFactory.getLog(DefaultKeyStrategy.class);

    private static final Pattern CLEAN_PATTERN = Pattern.compile("\\s");

    private int maxKeyLength = DEFAULT_MAX_KEY_LENGTH;

    public String toKey(String regionName, long clearIndex, Object key) {
        String keyString = convertKeyToString(regionName, clearIndex, key);
        if (keyString.length() > maxKeyLength) {
            return truncateKey(keyString);
        }
        return CLEAN_PATTERN.matcher(keyString).replaceAll("");
    }

    protected String truncateKey(String key) {
        String uuidString = UUID.nameUUIDFromBytes(key.getBytes()).toString();

        if (log.isWarnEnabled()) {
            log.warn("Truncated key [" + key + "] to uuid [" + uuidString + "]. " +
                    "Be sure to set cache region names whenever possible as the names Hibernate generates are really long. " +
                    "Consider using the UUIDKeyStrategy when hibernate.cache.use_query_cache is enabled."
            );
        }

        return uuidString;
    }

    public int getMaxKeyLength() {
        return maxKeyLength;
    }

    public void setMaxKeyLength(int maxKeyLength) {
        this.maxKeyLength = maxKeyLength;
    }
}
